home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / mail / pine3.96.tar.gz / pine3.96.tar / pine3.96 / imap / ANSI / c-client / tcp_mac.c < prev    next >
C/C++ Source or Header  |  1995-09-09  |  15KB  |  502 lines

  1. /*
  2.  * Program:    Macintosh TCP/IP routines
  3.  *
  4.  * Author:    Mark Crispin
  5.  *        6158 Lariat Loop NE
  6.  *        Bainbridge Island, WA  98110-2098
  7.  *        Internet: MRC@Panda.COM
  8.  *
  9.  * Date:    26 January 1992
  10.  * Last Edited:    8 September 1995
  11.  *
  12.  * Copyright 1995 by Mark Crispin
  13.  *
  14.  *  Permission to use, copy, modify, and distribute this software and its
  15.  * documentation for any purpose and without fee is hereby granted, provided
  16.  * that the above copyright notice appears in all copies and that both the
  17.  * above copyright notices and this permission notice appear in supporting
  18.  * documentation, and that the name of Mark Crispin not be used in advertising
  19.  * or publicity pertaining to distribution of the software without specific,
  20.  * written prior permission.  This software is made available "as is", and
  21.  * MARK CRISPIN DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO
  22.  * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF
  23.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL
  24.  * MARK CRISPIN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES
  25.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  26.  * WHETHER IN AN ACTION OF CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT
  27.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
  28.  * THIS SOFTWARE.
  29.  *
  30.  */
  31.  
  32.  
  33. /*  This is a totally new operating-system dependent module for the Macintosh,
  34.  * written using THINK C on my Mac PowerBook-100 in my free time.
  35.  * Unlike earlier efforts, this version requires no external TCP library.  It
  36.  * also takes advantage of the Map panel in System 7 for the timezone.
  37.  */
  38.  
  39.                 /* TCP timeout handler routine */
  40. static tcptimeout_t tcptimeout = NIL;
  41.                 /* TCP timeouts, in seconds */
  42. static long tcptimeout_open = 75;
  43. static long tcptimeout_read = 0;
  44. static long tcptimeout_write = 0;
  45. static long tcptimeout_close = 0;
  46.  
  47. /* TCP/IP manipulate parameters
  48.  * Accepts: function code
  49.  *        function-dependent value
  50.  * Returns: function-dependent return value
  51.  */
  52.  
  53. void *tcp_parameters (long function,void *value)
  54. {
  55.   switch ((int) function) {
  56.   case SET_TIMEOUT:
  57.     tcptimeout = (tcptimeout_t) value;
  58.     break;
  59.   case GET_TIMEOUT:
  60.     value = (void *) tcptimeout;
  61.     break;
  62.   case SET_OPENTIMEOUT:
  63.     tcptimeout_open = (long) value;
  64.     break;
  65.   case GET_OPENTIMEOUT:
  66.     value = (void *) tcptimeout_open;
  67.     break;
  68.   case SET_READTIMEOUT:
  69.     tcptimeout_read = (long) value;
  70.     break;
  71.   case GET_READTIMEOUT:
  72.     value = (void *) tcptimeout_read;
  73.     break;
  74.   case SET_WRITETIMEOUT:
  75.     tcptimeout_write = (long) value;
  76.     break;
  77.   case GET_WRITETIMEOUT:
  78.     value = (void *) tcptimeout_write;
  79.     break;
  80.   case SET_CLOSETIMEOUT:
  81.     tcptimeout_close = (long) value;
  82.     break;
  83.   case GET_CLOSETIMEOUT:
  84.     value = (void *) tcptimeout_close;
  85.     break;
  86.   default:
  87.     value = NIL;        /* error case */
  88.     break;
  89.   }
  90.   return value;
  91. }
  92.  
  93. /* TCP/IP open
  94.  * Accepts: host name
  95.  *        contact service name
  96.  *        contact port number
  97.  * Returns: TCP stream if success else NIL
  98.  */
  99.  
  100. TCPSTREAM *tcp_open (char *host,char *service,long port)
  101. {
  102.   TCPSTREAM *stream;
  103.   struct hostInfo hst;
  104.   struct TCPCreatePB *createpb;
  105.   struct TCPOpenPB *openpb;
  106.   char *s;
  107.   unsigned long i,j,k,l;
  108.   char tmp[MAILTMPLEN];
  109.                 /* init MacTCP */
  110.   if (!TCPdriver && OpenDriver (TCPDRIVER,&TCPdriver)) {
  111.     mm_log ("Can't init MacTCP",ERROR);
  112.     return NIL;
  113.   }
  114.   if (!resolveropen && OpenResolver (NIL)) {
  115.     mm_log ("Can't init domain resolver",ERROR);
  116.     return NIL;
  117.   }
  118.   resolveropen = T;        /* note resolver open now */
  119.   if (s = strchr (host,':')) {    /* port number specified? */
  120.     *s++ = '\0';        /* yes, tie off port */
  121.     port = strtol (s,&s,10);    /* parse port */
  122.     if (s && *s) {
  123.       sprintf (tmp,"Junk after port number: %.80s",s);
  124.       mm_log (tmp,ERROR);
  125.       return NIL;
  126.     }
  127.   }
  128.                 /* domain literal? */
  129.   if (host[0] == '[' && host[strlen (host)-1] == ']') {
  130.     if (((i = strtol (s = host+1,&s,10)) <= 255) && *s++ == '.' &&
  131.     ((j = strtol (s,&s,10)) <= 255) && *s++ == '.' &&
  132.     ((k = strtol (s,&s,10)) <= 255) && *s++ == '.' &&
  133.     ((l = strtol (s,&s,10)) <= 255) && *s++ == ']' && !*s) {
  134.       hst.addr[0] = (i << 24) + (j << 16) + (k << 8) + l;
  135.       hst.addr[1] = 0;        /* only one address to try! */
  136.       sprintf (hst.cname,"[%ld.%ld.%ld.%ld]",i,j,k,l);
  137.     }
  138.     else {
  139.       sprintf (tmp,"Bad format domain-literal: %.80s",host);
  140.       mm_log (tmp,ERROR);
  141.       return NIL;
  142.     }
  143.   }
  144.  
  145.   else {            /* look up host name */
  146.     if (!tcp_dns_upp) tcp_dns_upp = NewResultProc (tcp_dns_result);
  147.     if (StrToAddr (host,&hst,tcp_dns_upp,NIL)) {
  148.       while (hst.rtnCode == cacheFault && wait ());
  149.                 /* kludge around MacTCP bug */
  150.       if (hst.rtnCode == outOfMemory) {
  151.     mm_log ("Re-initializing domain resolver",WARN);
  152.     CloseResolver ();    /* bop it on the head and try again */
  153.     OpenResolver (NIL);    /* note this will leak 12K */
  154.     StrToAddr (host,&hst,tcp_dns_upp,NIL);
  155.     while (hst.rtnCode == cacheFault && wait ());
  156.       }
  157.       if (hst.rtnCode) {    /* still have error status? */
  158.     switch (hst.rtnCode) {    /* analyze return */
  159.     case nameSyntaxErr:
  160.       s = "Syntax error in name";
  161.       break;
  162.     case noResultProc:
  163.       s = "No result procedure";
  164.       break;
  165.     case noNameServer:
  166.       s = "No name server found";
  167.       break;
  168.     case authNameErr:
  169.       s = "Host does not exist";
  170.       break;
  171.     case noAnsErr:
  172.       s = "No name servers responding";
  173.       break;
  174.     case dnrErr:
  175.       s = "Name server returned an error";
  176.       break;
  177.     case outOfMemory:
  178.       s = "Not enough memory to resolve name";
  179.       break;
  180.     case notOpenErr:
  181.       s = "Driver not open";
  182.       break;
  183.     default:
  184.       s = NIL;
  185.       break;
  186.     }
  187.     if (s) sprintf (tmp,"%s: %.80s",s,host);
  188.     else sprintf (tmp,"Unknown resolver error (%ld): %.80s",
  189.               hst.rtnCode,host);
  190.     mm_log (tmp,ERROR);
  191.     return NIL;
  192.       }
  193.     }
  194.   }
  195.  
  196.                 /* create local TCP/IP stream */
  197.   stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
  198.   stream->ictr = 0;        /* initialize input */
  199.   stream->pb.ioCRefNum = TCPdriver;
  200.   createpb = &stream->pb.csParam.create;
  201.   openpb = &stream->pb.csParam.open;
  202.   stream->pb.csCode = TCPCreate;/* create a TCP stream */
  203.                 /* set up buffer for TCP */
  204.   createpb->rcvBuffLen = 4*BUFLEN;
  205.   createpb->rcvBuff = fs_get (createpb->rcvBuffLen);
  206.   createpb->notifyProc = NIL;    /* no special notify procedure */
  207.   createpb->userDataPtr = NIL;
  208.   if (PBControlSync ((ParmBlkPtr) &stream->pb))
  209.     fatal ("Can't create TCP stream");
  210.                   /* open TCP connection */
  211.   stream->pb.csCode = TCPActiveOpen;
  212.   openpb->ulpTimeoutValue = (int) tcptimeout_open;
  213.   openpb->ulpTimeoutAction = T;
  214.   openpb->validityFlags = timeoutValue|timeoutAction;
  215.                 /* remote host (should try all) */
  216.   openpb->remoteHost = hst.addr[0];
  217.   openpb->remotePort = port;    /* caller specified remote port */
  218.   openpb->localPort = 0;    /* generate a local port */
  219.   openpb->tosFlags = 0;        /* no special TOS */
  220.   openpb->precedence = 0;    /* no special precedence */
  221.   openpb->dontFrag = 0;        /* allow fragmentation */
  222.   openpb->timeToLive = 255;    /* standards say 60, UNIX uses 255 */
  223.   openpb->security = 0;        /* no special security */
  224.   openpb->optionCnt = 0;    /* no IP options */
  225.   openpb->options[0] = 0;
  226.   openpb->userDataPtr = NIL;    /* no special data pointer */
  227.   PBControlAsync ((ParmBlkPtr) &stream->pb);
  228.   while (stream->pb.ioResult == inProgress && wait ());
  229.   if (stream->pb.ioResult) {    /* got back error status? */
  230.     sprintf (tmp,"Can't connect to %.80s,%ld",hst.cname,port);
  231.     mm_log (tmp,ERROR);
  232.                 /* nuke the buffer */
  233.     stream->pb.csCode = TCPRelease;
  234.     createpb->userDataPtr = NIL;
  235.     if (PBControlSync ((ParmBlkPtr) &stream->pb)) fatal ("TCPRelease lossage");
  236.                 /* free its buffer */
  237.     fs_give ((void **) &createpb->rcvBuff);
  238.     fs_give ((void **) &stream);/* and the local stream */
  239.     return NIL;
  240.   }
  241.  
  242.                 /* copy host names for later use */
  243.   stream->host = cpystr (hst.cname);
  244.                 /* tie off trailing dot */
  245.   stream->host[strlen (stream->host) - 1] = '\0';
  246.                 /* the open gave us our address */
  247.   i = (openpb->localHost >> 24) & 0xff;
  248.   j = (openpb->localHost >> 16) & 0xff;
  249.   k = (openpb->localHost >> 8) & 0xff;
  250.   l = openpb->localHost & 0xff;
  251.   sprintf (tmp,"[%ld.%ld.%ld.%ld]",i,j,k,l);
  252.   stream->localhost = cpystr (tmp);
  253.   if (!myLocalHost) myLocalHost = cpystr (tmp);
  254.   stream->port = port;        /* copy port number */
  255.   return stream;
  256. }
  257.  
  258.  
  259. /* Called when have return from DNS
  260.  * Accepts: host info pointer
  261.  *        user data pointer
  262.  */
  263.  
  264. ResultUPP tcp_dns_upp = NIL;
  265.  
  266. pascal void tcp_dns_result (struct hostInfo *hostInfoPtr,char *userDataPtr)
  267. {
  268.   /* dummy routine */
  269. }
  270.  
  271. /* TCP/IP authenticated open
  272.  * Accepts: host name
  273.  *        service name
  274.  *        returned user name
  275.  * Returns : TCP/IP stream if success else NIL
  276.  */
  277.  
  278. TCPSTREAM *tcp_aopen (char *host,char *service,char *usrnam)
  279. {
  280.   return NIL;            /* no authenticated opens on Mac */
  281. }
  282.  
  283. /* TCP/IP receive line
  284.  * Accepts: TCP/IP stream
  285.  * Returns: text line string or NIL if failure
  286.  */
  287.  
  288. char *tcp_getline (TCPSTREAM *stream)
  289. {
  290.   int n,m;
  291.   char *st,*ret,*stp;
  292.   char c = '\0';
  293.   char d;
  294.                 /* make sure have data */
  295.   if (!tcp_getdata (stream)) return NIL;
  296.   st = stream->iptr;        /* save start of string */
  297.   n = 0;            /* init string count */
  298.   while (stream->ictr--) {    /* look for end of line */
  299.     d = *stream->iptr++;    /* slurp another character */
  300.     if ((c == '\015') && (d == '\012')) {
  301.       ret = (char *) fs_get (n--);
  302.       memcpy (ret,st,n);    /* copy into a free storage string */
  303.       ret[n] = '\0';        /* tie off string with null */
  304.       return ret;
  305.     }
  306.     n++;            /* count another character searched */
  307.     c = d;            /* remember previous character */
  308.   }
  309.                 /* copy partial string from buffer */
  310.   memcpy ((ret = stp = (char *) fs_get (n)),st,n);
  311.                 /* get more data from the net */
  312.   if (!tcp_getdata (stream)) return NIL;
  313.                 /* special case of newline broken by buffer */
  314.   if ((c == '\015') && (*stream->iptr == '\012')) {
  315.     stream->iptr++;        /* eat the line feed */
  316.     stream->ictr--;
  317.     ret[n - 1] = '\0';        /* tie off string with null */
  318.   }
  319.                 /* else recurse to get remainder */
  320.   else if (st = tcp_getline (stream)) {
  321.     ret = (char *) fs_get (n + 1 + (m = strlen (st)));
  322.     memcpy (ret,stp,n);        /* copy first part */
  323.     memcpy (ret + n,st,m);    /* and second part */
  324.     fs_give ((void **) &stp);    /* flush first part */
  325.     fs_give ((void **) &st);    /* flush second part */
  326.     ret[n + m] = '\0';        /* tie off string with null */
  327.   }
  328.   return ret;
  329. }
  330.  
  331. /* TCP/IP receive buffer
  332.  * Accepts: TCP/IP stream
  333.  *        size in bytes
  334.  *        buffer to read into
  335.  * Returns: T if success, NIL otherwise
  336.  */
  337.  
  338. long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
  339. {
  340.   unsigned long n;
  341.   char *bufptr = buffer;
  342.   while (size > 0) {        /* until request satisfied */
  343.     if (!tcp_getdata (stream)) return NIL;
  344.     n = min (size,stream->ictr);/* number of bytes to transfer */
  345.                 /* do the copy */
  346.     memcpy (bufptr,stream->iptr,n);
  347.     bufptr += n;        /* update pointer */
  348.     stream->iptr +=n;
  349.     size -= n;            /* update # of bytes to do */
  350.     stream->ictr -=n;
  351.   }
  352.   bufptr[0] = '\0';        /* tie off string */
  353.   return T;
  354. }
  355.  
  356.  
  357. /* TCP/IP receive data
  358.  * Accepts: TCP/IP stream
  359.  * Returns: T if success, NIL otherwise
  360.  */
  361.  
  362. long tcp_getdata (TCPSTREAM *stream)
  363. {
  364.   time_t t = time (0);
  365.   struct TCPReceivePB *receivepb = &stream->pb.csParam.receive;
  366.   struct TCPAbortPB *abortpb = &stream->pb.csParam.abort;
  367.   while (stream->ictr < 1) {    /* if nothing in the buffer */
  368.     stream->pb.csCode = TCPRcv;    /* receive TCP data */
  369.     receivepb->commandTimeoutValue = (int) tcptimeout_read;
  370.     receivepb->rcvBuff = stream->ibuf;
  371.     receivepb->rcvBuffLen = BUFLEN;
  372.     receivepb->secondTimeStamp = 0;
  373.     receivepb->userDataPtr = NIL;
  374.     PBControlAsync ((ParmBlkPtr) &stream->pb);
  375.     while (stream->pb.ioResult == inProgress && wait ());
  376.     if ((stream->pb.ioResult == commandTimeout) && tcptimeout &&
  377.     ((*tcptimeout) (time (0) - t))) continue;
  378.     if (stream->pb.ioResult) {    /* punt if got an error */
  379.                     /* nuke connection */
  380.       stream->pb.csCode = TCPAbort;
  381.       abortpb->userDataPtr = NIL;
  382.       PBControlSync ((ParmBlkPtr) &stream->pb);
  383.       return NIL;
  384.     }
  385.     stream->iptr = stream->ibuf;/* point at TCP buffer */
  386.     stream->ictr = receivepb->rcvBuffLen;
  387.   }
  388.   return T;
  389. }
  390.  
  391. /* TCP/IP send string as record
  392.  * Accepts: TCP/IP stream
  393.  *        string pointer
  394.  * Returns: T if success else NIL
  395.  */
  396.  
  397. long tcp_soutr (TCPSTREAM *stream,char *string)
  398. {
  399.   return tcp_sout (stream,string,(unsigned long) strlen (string));
  400. }
  401.  
  402.  
  403. /* TCP/IP send string
  404.  * Accepts: TCP/IP stream
  405.  *        string pointer
  406.  *        byte count
  407.  * Returns: T if success else NIL
  408.  */
  409.  
  410. long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
  411. {
  412.   struct TCPSendPB *sendpb = &stream->pb.csParam.send;
  413.   struct TCPAbortPB *abortpb = &stream->pb.csParam.abort;
  414.   struct {
  415.     unsigned short length;
  416.     Ptr buffer;
  417.     unsigned short trailer;
  418.   } wds;
  419.   while (wds.length = (size > (unsigned long) 32768) ? 32768 : size) {
  420.     wds.buffer = string;    /* buffer */
  421.     wds.trailer = 0;        /* tie off buffer */
  422.     size -= wds.length;        /* this many words will be output */
  423.     string += wds.length;
  424.     stream->pb.csCode = TCPSend;/* send TCP data */
  425.     sendpb->ulpTimeoutValue = (int) tcptimeout_write;
  426.     sendpb->ulpTimeoutAction = 0;
  427.     sendpb->validityFlags = timeoutValue|timeoutAction;
  428.     sendpb->pushFlag = T;    /* send the data now */
  429.     sendpb->urgentFlag = NIL;    /* non-urgent data */
  430.     sendpb->wdsPtr = (Ptr) &wds;
  431.     sendpb->userDataPtr = NIL;
  432.     PBControlAsync ((ParmBlkPtr) &stream->pb);
  433.     while (stream->pb.ioResult == inProgress && wait ());
  434.     if (stream->pb.ioResult) {    /* punt if got an error */
  435.                 /* nuke connection */
  436.       stream->pb.csCode =TCPAbort;
  437.       abortpb->userDataPtr = NIL;
  438.       PBControlSync ((ParmBlkPtr) &stream->pb);
  439.       return NIL;
  440.     }
  441.   }
  442.   return T;            /* success */
  443. }
  444.  
  445. /* TCP/IP close
  446.  * Accepts: TCP/IP stream
  447.  */
  448.  
  449. void tcp_close (TCPSTREAM *stream)
  450. {
  451.   struct TCPClosePB *closepb = &stream->pb.csParam.close;
  452.   struct TCPCreatePB *createpb = &stream->pb.csParam.create;
  453.   stream->pb.csCode = TCPClose;    /* close TCP stream */
  454.   closepb->ulpTimeoutValue = (int) tcptimeout_close;
  455.   closepb->ulpTimeoutAction = 0;
  456.   closepb->validityFlags = timeoutValue|timeoutAction;
  457.   closepb->userDataPtr = NIL;
  458.   PBControlAsync ((ParmBlkPtr) &stream->pb);
  459.   while (stream->pb.ioResult == inProgress && wait ());
  460.   stream->pb.csCode =TCPRelease;/* flush the buffers */
  461.   createpb->userDataPtr = NIL;
  462.   if (PBControlSync ((ParmBlkPtr) &stream->pb)) fatal ("TCPRelease lossage");
  463.                 /* free its buffer */
  464.   fs_give ((void **) &createpb->rcvBuff);
  465.                 /* flush host names */
  466.   fs_give ((void **) &stream->host);
  467.   fs_give ((void **) &stream->localhost);
  468.   fs_give ((void **) &stream);    /* flush the stream */
  469. }
  470.  
  471. /* TCP/IP return host for this stream
  472.  * Accepts: TCP/IP stream
  473.  * Returns: host name for this stream
  474.  */
  475.  
  476. char *tcp_host (TCPSTREAM *stream)
  477. {
  478.   return stream->host;        /* return host name */
  479. }
  480.  
  481.  
  482. /* TCP/IP return port for this stream
  483.  * Accepts: TCP/IP stream
  484.  * Returns: port number for this stream
  485.  */
  486.  
  487. long tcp_port (TCPSTREAM *stream)
  488. {
  489.   return stream->port;        /* return port number */
  490. }
  491.  
  492.  
  493. /* TCP/IP return local host for this stream
  494.  * Accepts: TCP/IP stream
  495.  * Returns: local host name for this stream
  496.  */
  497.  
  498. char *tcp_localhost (TCPSTREAM *stream)
  499. {
  500.   return stream->localhost;    /* return local host name */
  501. }
  502.